home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 November / PCWNOV08.iso / Software / Freeware / NoScript 1.7.7 / noscript-1.7.7-fx+mz+sm.xpi / chrome / noscript.jar / content / noscript / noscriptOverlay.js < prev    next >
Encoding:
JavaScript  |  2008-07-14  |  55.9 KB  |  1,701 lines

  1. /***** BEGIN LICENSE BLOCK *****
  2.  
  3. NoScript - a Firefox extension for whitelist driven safe JavaScript execution
  4. Copyright (C) 2004-2008 Giorgio Maone - g.maone@informaction.com
  5.  
  6. Contributors: 
  7.   Higmmer
  8.  
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13.  
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with this program; if not, write to the Free Software
  21. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22.  
  23. ***** END LICENSE BLOCK *****/
  24.  
  25.  
  26. var noscriptOverlay = noscriptUtil.service ? 
  27. {
  28.   ns: noscriptUtil.service,
  29.   
  30.   getString: function(key, parms) {
  31.     return noscriptUtil.getString(key, parms);
  32.   }
  33. ,
  34.   toggleCurrentPage: function(force) {
  35.     const ns = this.ns;
  36.     var level = ns.getPref("toolbarToggle", 3) || force;
  37.     if (!level) return false;
  38.     
  39.     const url = ns.getQuickSite(content.document.documentURI, level);
  40.     if (url)
  41.       this.safeAllow(url, !ns.isJSEnabled(url), ns.getPref("toggle.temp"));
  42.     return true;
  43.   },
  44.  
  45.   
  46.   getSites: function() {
  47.     return this.ns.getSites(gBrowser.selectedBrowser);
  48.   },
  49.   
  50.   get prompter() {
  51.     return noscriptUtil.prompter;
  52.   },
  53.   
  54.   onMenuShowing: function(ev) {
  55.     if (ev.currentTarget != ev.originalTarget) return;
  56.     this.prepareMenu(ev.target);
  57.   },
  58.  
  59.   prepareContextMenu: function(ev) {
  60.     var menu = document.getElementById("noscript-context-menu");
  61.     if (this.ns.getPref("ctxMenu", true)) {
  62.       menu.removeAttribute("hidden");
  63.     } else {
  64.       menu.setAttribute("hidden", "true");
  65.       return;
  66.     }
  67.     this.updateStatusClass(menu);
  68.     menu.setAttribute("tooltiptext", this.statusIcon.getAttribute("tooltiptext"));
  69.   }
  70. ,
  71.   toggleMenuOpt: function(node) {
  72.     var val=node.getAttribute("checked")=="true";
  73.     var k=node.id.lastIndexOf("-opt-");
  74.     if (k>-1) {
  75.       this.ns.setPref(node.id.substring(5+k),val);
  76.     }
  77.     return val;
  78.   }
  79. ,
  80.  
  81.   prepareOptItems: function(popup) {
  82.     const notifications = this.getNotificationBox();
  83.     const opts = popup.getElementsByAttribute("type", "checkbox");
  84.     var k, j, node, id;
  85.     for (j = opts.length; j-- > 0;) {
  86.       node = opts[j];
  87.       var id = node.id;
  88.       if ((k = id.lastIndexOf("-opt-")) > -1) {
  89.         if ((!notifications) && id.indexOf("notification") - 1) {
  90.           node.setAttribute("hidden", "true");
  91.         } else {
  92.           node.setAttribute("checked", this.ns.getPref(node.id.substring(5 + k)));
  93.         }
  94.       }
  95.     }
  96.   },
  97.   
  98.   
  99.   prepareXssMenu: function(popup, invert) {
  100.     this.prepareOptItems(this.populateXssMenu(popup, invert));
  101.   },
  102.   populateXssMenu: function(popup, invert) {
  103.     var ref = document.getElementById("noscript-mi-xss-unsafe-reload");
  104.     var parent = ref.parentNode;
  105.     var inverse = parent.lastChild.id != "noscript-mi-xss-faq";
  106.     invert = inverse && !invert;
  107.     if (parent != popup) {
  108.       while (parent.firstChild) {
  109.         popup.appendChild(invert ? parent.lastChild : parent.firstChild);
  110.       }
  111.     } else if (invert) {
  112.       for (var p, n = parent.lastChild; n; n = p) {
  113.         p = n.previousSibling;
  114.         parent.appendChild(n);
  115.       }
  116.     }
  117.     
  118.     return popup;
  119.   },
  120.   
  121.   prepareMenu: function(popup) {
  122.     const ns = this.ns;
  123.  
  124.     var j, k, node;
  125.     
  126.     const global = ns.jsEnabled;
  127.     const blockUntrusted = global && ns.alwaysBlockUntrustedContent;
  128.     
  129.     var allSeps = popup.getElementsByTagName("menuseparator");
  130.    
  131.     var seps = { insert: null, stop: null, global: null, untrusted: null };
  132.     var sepName;
  133.     for (j = allSeps.length; j-- > 0;) {
  134.       sepName = (node = allSeps[j]).className;
  135.       node.hidden = false;
  136.       for (k in seps) {
  137.         if (sepName.indexOf("-" + k) > -1) {
  138.           seps[k] = node;
  139.         }
  140.       }
  141.     }
  142.     
  143.     delete allSeps;
  144.  
  145.     const miGlobal = seps.global.nextSibling;
  146.     
  147.     if (global || ns.getPref("showGlobal")) {
  148.       miGlobal.hidden = seps.global.hidden = false;
  149.       miGlobal.setAttribute("label", this.getString((global ? "forbid" : "allow") + "Global"));
  150.       miGlobal.setAttribute("oncommand","noscriptOverlay.menuAllow("+(!global)+")");
  151.       miGlobal.setAttribute("tooltiptext", this.statusIcon.getAttribute("tooltiptext"));
  152.       miGlobal.setAttribute("class", "menuitem-iconic noscript-glb " + this.getStatusClass(global ? "no" : "yes"));
  153.     } else {
  154.       miGlobal.hidden = seps.global.hidden = true;
  155.     }
  156.     
  157.     node = miGlobal.nextSibling;
  158.     const mainMenu = node.parentNode;
  159.     
  160.     var tempMenuItem = document.getElementById("noscript-revoke-temp-mi");
  161.     if (node != tempMenuItem) {
  162.       node = mainMenu.insertBefore(tempMenuItem, node);
  163.     }
  164.     
  165.     if ((ns.tempSites.sitesString || ns.objectWhitelistLen) && ns.getPref("showRevokeTemp", true)) {
  166.       node.hidden = seps.global.hidden = false;
  167.       node.setAttribute("tooltiptext",
  168.         // remove http/https/file CAPS hack entries 
  169.         "<SCRIPT>: " + 
  170.         (ns.tempSites.sitesString 
  171.           ? ns.siteUtils.sanitizeString(ns.tempSites.sitesString.replace(/\b(?:https?|file):\/\//g, ""
  172.               )).split(/\s+/) 
  173.               // .join(",\n") // wait Firefox 3 with its multiline tooltips for this
  174.               .length
  175.           : 0) +
  176.         " | <OBJECT>: " + ns.objectWhitelistLen
  177.       );
  178.     } else {
  179.       node.hidden = true;
  180.     }
  181.     node = node.nextSibling;
  182.     
  183.     tempMenuItem = document.getElementById("noscript-temp-allow-page-mi");
  184.     if (node != tempMenuItem) {
  185.       mainMenu.insertBefore(tempMenuItem, node)
  186.     } else {
  187.       node = node.nextSibling;
  188.     }
  189.     
  190.     var xssMenu = document.getElementById("noscript-xss-menu");
  191.     
  192.     if (xssMenu && node != xssMenu) {
  193.       mainMenu.insertBefore(xssMenu, node);
  194.     }
  195.     this.populateXssMenu(xssMenu.firstChild);
  196.     this.syncXssWidget(xssMenu);
  197.     
  198.  
  199.     this.prepareOptItems(popup);
  200.       
  201.     var untrustedMenu = null;
  202.     var pluginsMenu = null;
  203.     if (seps.untrusted) {
  204.       
  205.       pluginsMenu = document.getElementById("noscript-menu-blocked-objects");
  206.       untrustedMenu = document.getElementById("noscript-menu-untrusted");
  207.       // cleanup untrustedCount display
  208.       untrustedMenu.setAttribute("label", untrustedMenu.getAttribute("label").replace(/ \(\d+\)$/, ""));
  209.       
  210.       with(seps.untrusted) {
  211.         if (nextSibling != pluginsMenu) {   
  212.           parentNode.insertBefore(untrustedMenu, nextSibling);
  213.           parentNode.insertBefore(pluginsMenu, untrustedMenu);
  214.         }
  215.       }
  216.       // descend from menus to popups and clear children
  217.       for each(node in [pluginsMenu = pluginsMenu.firstChild, untrustedMenu = untrustedMenu.firstChild])
  218.         while (node.firstChild)
  219.           node.removeChild(node.firstChild);
  220.       untrustedMenu.appendCmd = untrustedMenu.appendChild;
  221.     }
  222.     
  223.     node = seps.insert.nextSibling;
  224.     
  225.     var remNode;
  226.     while (node && (node != seps.stop)) {
  227.        remNode = node;
  228.        node = node.nextSibling;
  229.        if (remNode != untrustedMenu && remNode != xssMenu)
  230.          mainMenu.removeChild(remNode);
  231.     }
  232.  
  233.     mainMenu.appendCmd = function(n) { this.insertBefore(n, seps.stop); };
  234.  
  235.     const sites = this.getSites();
  236.     j = sites.indexOf(sites.topURL);
  237.     if (j > 0) {
  238.       sites.splice(j, 1);
  239.       sites.push(sites.topURL);
  240.     }
  241.     
  242.     
  243.     try {
  244.       this.populatePluginsMenu(mainMenu, pluginsMenu, sites.pluginExtras);
  245.     } catch(e) {
  246.       if(ns.consoleDump) ns.dump("Error populating plugins menu: " + e);
  247.     }
  248.     var site, enabled, isTop, lev;
  249.     var jsPSs = ns.jsPolicySites;
  250.     var matchingSite;
  251.     var menuGroups, menuSites, menuSite, scount;
  252.     var domain, pos, baseLen, dp;
  253.     var untrusted;
  254.     var cssClass;
  255.  
  256.     var domainDupChecker = {
  257.       domains: {},
  258.       check: function(d) {
  259.         return this.domains[d] || !(this.domains[d] = true);
  260.       }
  261.     };
  262.     
  263.     const locked = ns.locked;
  264.     const showAddress = locked || ns.getPref("showAddress", false);
  265.     const showDomain = !locked && ns.getPref("showDomain", false);
  266.     const showBase = !locked && ns.getPref("showBaseDomain", true);
  267.     const showUntrusted = ns.getPref("showUntrusted", true);
  268.     const showDistrust = ns.getPref("showDistrust", true);
  269.     const showNothing = !(showAddress || showDomain || showBase || showUntrust);
  270.     const forbidImpliesUntrust = ns.forbidImpliesUntrust;
  271.     
  272.     const showPermanent = ns.getPref("showPermanent", true);
  273.     const showTemp = !locked && ns.getPref("showTemp", true);
  274.     
  275.     var parent, extraNode;
  276.     var untrustedCount = 0, unknownCount = 0;
  277.     const untrustedSites = ns.untrustedSites;
  278.     var docJSBlocked = false;
  279.     
  280.     menuGroups = [];
  281.     for (j = sites.length; j-- > 0;) {
  282.       site = sites[j];
  283.       
  284.       matchingSite = jsPSs.matches(site);
  285.       untrusted = untrustedSites.matches(site);
  286.       if (untrusted) {
  287.         matchingSite = null;
  288.       } else if (blockUntrusted && !matchingSite) {
  289.         matchingSite = site;
  290.       }
  291.       
  292.       isTop = site == sites.topURL;
  293.       enabled = !!matchingSite;
  294.       docJSBlocked = enabled && isTop && !gBrowser.selectedBrowser.webNavigation.allowJavascript;
  295.       if (docJSBlocked) enabled = false;
  296.       
  297.       if (enabled && !global || (matchingSite = untrusted)) {
  298.         if (domainDupChecker.check(matchingSite)) continue;
  299.         menuSites = [matchingSite];
  300.       } else {
  301.         domain = ns.getDomain(site);
  302.         
  303.         if (domain && (dp = ns.getPublicSuffix(domain)) == domain) 
  304.           domain = null; // exclude TLDs
  305.         
  306.         menuSites = (showAddress || showNothing || !domain) ? [site] : [];
  307.         if (domain && (showDomain || showBase)) {
  308.           baseLen = domain.length;
  309.           if (dp) 
  310.             baseLen -= (domain.lastIndexOf(".", baseLen - dp.length - 2) + 1); 
  311.           if (baseLen == domain.length) {
  312.             // IP or 2nd level domain
  313.             if (!domainDupChecker.check(domain)) {
  314.               menuSites.push(domain);
  315.             }
  316.           } else {
  317.             dp = domain;
  318.             for (pos = 0; (pos = domain.indexOf('.', pos)) > 0; dp = domain.substring(++pos)) {
  319.               if (baseLen == dp.length) {
  320.                 if (menuSites.length > 0 && !showBase) continue;
  321.               } else {
  322.                 if (!showDomain) continue;
  323.               }
  324.               if (!domainDupChecker.check(dp)) {
  325.                 menuSites.push(dp);
  326.               }
  327.               if (baseLen == dp.length) break;
  328.             }
  329.           }
  330.         }  
  331.       }
  332.       menuSites.isTop = isTop;
  333.       menuSites.enabled = enabled;
  334.       menuGroups.push(menuSites);
  335.     }
  336.     
  337.     for (j = menuGroups.length; j-- > 0;) {
  338.  
  339.       if (seps.stop.previousSibling.nodeName != "menuseparator") {
  340.         mainMenu.appendCmd(document.createElement("menuseparator"));
  341.       }
  342.       
  343.       menuSites = menuGroups[j];
  344.       isTop = menuSites.isTop;
  345.       enabled = menuSites.enabled;
  346.       
  347.       for (scount = menuSites.length; scount-- > 0;) {
  348.         menuSite = menuSites[scount];
  349.         
  350.         untrusted = !enabled && (blockUntrusted || ns.isUntrusted(menuSite));
  351.         if (untrusted) 
  352.           untrustedCount++;
  353.         else if (!enabled)
  354.           unknownCount++;
  355.         
  356.         parent = (untrusted && showUntrusted) ? untrustedMenu : mainMenu;
  357.         if (!parent) continue;
  358.         
  359.         node = document.createElement("menuitem");
  360.         cssClass = isTop ? "noscript-toplevel noscript-cmd" : "noscript-cmd";
  361.         
  362.         domain = isTop && docJSBlocked ? "[ " + menuSite + " ]" : menuSite;
  363.         
  364.         node.setAttribute("label", this.getString((enabled ? "forbidLocal" : "allowLocal"), [domain]));
  365.         node.setAttribute("statustext", menuSite);
  366.         node.setAttribute("oncommand", "noscriptOverlay.menuAllow(" + (!enabled) + ", this)");
  367.         node.setAttribute("tooltiptext",
  368.           this.getString("allowed." + (enabled ? "yes" : "no")));
  369.         if (locked || enabled && ns.isPermanent(menuSite)) {
  370.           node.setAttribute("disabled", "true");
  371.         } else {
  372.           cssClass += " menuitem-iconic ";
  373.           if (enabled && ns.isTemp(menuSite)) cssClass += " noscript-temp";
  374.         }
  375.         node.setAttribute("class", cssClass + (enabled ? " noscript-forbid" : " noscript-allow"));
  376.         
  377.         if (showPermanent || enabled) 
  378.           parent.appendCmd(node);
  379.         
  380.         if (!locked) {
  381.           if (showTemp && !enabled) {
  382.             extraNode = document.createElement("menuitem");
  383.             extraNode.setAttribute("label", this.getString("allowTemp", [domain]));
  384.             extraNode.setAttribute("statustext", menuSite);
  385.             extraNode.setAttribute("oncommand", "noscriptOverlay.menuAllow(true,this,true)");
  386.             extraNode.setAttribute("class", cssClass + " noscript-temp noscript-allow");
  387.             extraNode.setAttribute("tooltiptext", node.getAttribute("tooltiptext"));
  388.             parent.appendCmd(extraNode);
  389.           }
  390.           if (((showUntrusted && untrustedMenu) || showDistrust && !enabled) && !untrusted) {
  391.             extraNode = document.createElement("menuitem");
  392.             extraNode.setAttribute("label", this.getString("distrust", [menuSite]));
  393.             extraNode.setAttribute("statustext", menuSite);
  394.             extraNode.setAttribute("class", cssClass + " noscript-distrust");
  395.             extraNode.setAttribute("oncommand", "noscriptOverlay.menuAllow(false, this, false)");
  396.             extraNode.setAttribute("tooltiptext", node.getAttribute("tooltiptext"));
  397.             (showUntrusted ? untrustedMenu : mainMenu).appendCmd(extraNode);
  398.           }
  399.         }
  400.       }
  401.       
  402.       if (untrustedMenu && untrustedMenu.firstChild) {
  403.         untrustedMenu.appendCmd(document.createElement("menuseparator"));
  404.       }
  405.     }
  406.     if (untrustedMenu && untrustedMenu.firstChild) {
  407.       if (untrustedCount) 
  408.         with(untrustedMenu.parentNode)
  409.           setAttribute("label", getAttribute("label") +
  410.             " (" + untrustedCount + ")"); // see above for cleanup
  411.     }
  412.  
  413.     
  414.     
  415.     tempMenuItem.hidden = !(unknownCount && ns.getPref("showTempAllowPage", false));
  416.  
  417.     this.normalizeMenu(untrustedMenu, true);
  418.     this.normalizeMenu(mainMenu, false);
  419.     
  420.     if (mainMenu.id == "noscript-tbb-popup") { 
  421.       // this one can go away, better take our stuff back when done
  422.       mainMenu.addEventListener("popuphidden", function(ev) {
  423.         if (ev.target != ev.currentTarget) return;
  424.         ev.currentTarget.removeEventListener(ev.type, arguments.callee, false);
  425.         noscriptOverlay.prepareMenu(document.getElementById("noscript-status-popup"));
  426.       }, false);
  427.     }
  428.     
  429.   },
  430.  
  431.   populatePluginsMenu: function(mainMenu, menu, extras) {
  432.     if (!menu) return;
  433.     
  434.     menu.parentNode.hidden = true;
  435.     const ns = this.ns;
  436.     if (!(extras && ns.getPref("showBlockedObjects", true)))
  437.       return;
  438.     
  439.     var egroup, e, node, i;
  440.     var pluginExtras = [];
  441.     i = 0;
  442.     for each(egroup in extras) {
  443.       for each(e in egroup) {
  444.          
  445.          if(e.tag && !e.placeholder) continue;
  446.          node = document.createElement("menuitem");
  447.          
  448.          e.label = e.label || ns.mimeEssentials(e.mime) + "@" + ns.urlEssentials(e.url);
  449.          e.title = e.title || e.label.split("@")[0] + e.url;
  450.   
  451.          node.setAttribute("label", this.getString("allowTemp", [e.label]));
  452.          node.setAttribute("tooltiptext", e.title);
  453.          node.setAttribute("oncommand", "noscriptOverlay.allowObject(" + i + ")");
  454.          node.setAttribute("class", "menuitem-iconic noscript-cmd noscript-temp noscript-allow");
  455.          node.style.listStyleImage = ns.cssMimeIcon(e.mime, 16);
  456.          menu.appendChild(node);
  457.          pluginExtras[i++] = e;
  458.       }
  459.     }
  460.     if (i) {
  461.       noscriptOverlay.menuPluginExtras = pluginExtras;
  462.       mainMenu.addEventListener("popuphidden", function(ev) {
  463.           if (ev.currentTarget != ev.target) return;
  464.           ev.currentTarget.removeEventListener(ev.type, arguments.callee, false);
  465.           noscriptOverlay.menuPluginExtras = null;
  466.           noscriptOverlay.menuPluginSites = null;
  467.       }, false);
  468.       var pluginSites = {};
  469.       i = 0;
  470.       for each(e in pluginExtras) {
  471.         if(!(e.site && e.mime)) continue;
  472.         if (e.site in pluginSites) {
  473.           if (pluginSites[e.site].indexOf(e.mime) > -1) 
  474.             continue;
  475.           pluginSites[e.site].push(e.mime);
  476.         } else {
  477.           pluginSites[e.site] = ["*", e.mime];
  478.         }
  479.         i++;
  480.       }
  481.       if (i) {
  482.         noscriptOverlay.menuPluginSites = [];
  483.         i = 0;
  484.         var mime;
  485.         for (var site in pluginSites) {
  486.           menu.appendChild(document.createElement("menuseparator"));
  487.           for each(mime in pluginSites[site]) {
  488.             node = document.createElement("menuitem");
  489.             node.setAttribute("label", this.getString("allowTemp", [ns.mimeEssentials(mime) + "@" + site]));
  490.             node.setAttribute("tooltiptext", mime + "@" + site);
  491.             node.setAttribute("oncommand", "noscriptOverlay.allowObjectSite(" + i + ")");
  492.             node.setAttribute("class", "menuitem-iconic noscript-temp noscript-cmd noscript-allow");
  493.             if(mime != "*")
  494.               node.style.listStyleImage = node.style.listStyleImage = ns.cssMimeIcon(mime, 16);
  495.  
  496.             menu.appendChild(node);
  497.             noscriptOverlay.menuPluginSites[i++] = [site, mime];
  498.           }
  499.         }
  500.       }
  501.       menu.parentNode.hidden = false;
  502.     }
  503.   },
  504.   
  505.   allowPage: function(permanent) {
  506.     const ns = this.ns;
  507.     const sites = this.getSites();
  508.     const unknown = [];
  509.     const level = ns.getPref("allowPageLevel", 0) || ns.preferredSiteLevel;
  510.     var site;
  511.     for (var j = sites.length; j-- > 0;) {
  512.       site = ns.getQuickSite(sites[j], level);
  513.       if (!(ns.isJSEnabled(site) || ns.isUntrusted(site)))
  514.         unknown.push(site);
  515.     }
  516.     if (unknown.length) this.safeAllow(unknown, true, !permanent);
  517.   },
  518.   
  519.   allowObject: function(i) {
  520.     if(this.menuPluginExtras && this.menuPluginExtras[i]) {
  521.       var e = this.menuPluginExtras[i];
  522.       if(e.placeholder) {
  523.         this.ns.checkAndEnablePlaceholder(e.placeholder);
  524.       } else if (this.ns.confirmEnableObject(window, e)) {
  525.         this.allowObjectURL(e.url, e.mime);
  526.       }
  527.     }
  528.   },
  529.   
  530.   allowObjectSite: function(i) {
  531.     if(this.menuPluginSites && this.menuPluginSites[i]) {
  532.       this.allowObjectURL(this.menuPluginSites[i][0], this.menuPluginSites[i][1]);
  533.     }
  534.   },
  535.   allowObjectURL: function(url, mime) {
  536.     this.ns.allowObject(url, mime);
  537.     if (this.ns.getPref("autoReload", true))
  538.         this.ns.quickReload(gBrowser.selectedBrowser.webNavigation);
  539.   },
  540.   
  541.   normalizeMenu: function(menu, hideParentIfEmpty) {
  542.     if (!menu) return;
  543.     var prev = null;
  544.     var wasSep = true;
  545.     var isSep, haveMenu = false;
  546.     for (var i = menu.firstChild; i; i = i.nextSibling) {
  547.       if (!i.hidden) {
  548.         isSep = i.nodeName == "menuseparator";
  549.         if (isSep && wasSep) {
  550.           i.hidden = true;
  551.         } else {
  552.           haveMenu = haveMenu || !isSep;
  553.           prev = i;
  554.           wasSep = isSep;
  555.         }
  556.       }
  557.     }
  558.     
  559.     if (prev && wasSep) {
  560.       prev.hidden = true;
  561.     }
  562.     if (hideParentIfEmpty && menu.parentNode) {
  563.       menu.parentNode.hidden = !haveMenu;
  564.     }
  565.   }
  566. ,
  567.   getBrowserDoc: function(browser) {
  568.     return browser && browser.contentWindow && browser.contentWindow.document || null;
  569.   }
  570. ,
  571.   revokeTemp: function() {
  572.     const ns = noscriptOverlay.ns;
  573.     ns.safeCapsOp(function() {
  574.       ns.eraseTemp();
  575.       noscriptOverlay.syncUI();
  576.     }, !ns.getPref("autoReload.allTabsOnPageAction", true));
  577.   }
  578. ,
  579.   menuAllow: function(enabled, menuItem, temp) {
  580.     var site = null;
  581.     if (menuItem) { // local 
  582.       site = menuItem.getAttribute("statustext");
  583.       if (!site) return;
  584.       if (menuItem.getAttribute("class").indexOf("-distrust") > -1) {
  585.         this.ns.setUntrusted(site, true);
  586.       }
  587.     } else { // global
  588.       if (enabled && this.ns.getPref("globalwarning", true) &&
  589.           !this.prompter.confirm(window, this.getString("global.warning.title"),
  590.                                 this.getString("global.warning.text"))
  591.          ) return;
  592.     }
  593.     this.safeAllow(site, enabled, temp);
  594.   }
  595. ,
  596.   safeAllow: function(site, enabled, temp) {
  597.     const ns = this.ns;
  598.     var webNav = gBrowser.selectedBrowser.webNavigation;
  599.     var reloadCurrentTabOnly = (site instanceof Array) &&
  600.       !ns.getPref("autoReload.allTabsOnPageAction", true);
  601.  
  602.     ns.safeCapsOp(function() {
  603.       if (site) {
  604.         
  605.         ns.setTemp(site, enabled && temp);
  606.         ns.setJSEnabled(site, enabled, false, ns.mustCascadeTrust(site, temp));
  607.         
  608.         if (enabled && !webNav.allowJavascript) {
  609.           var curSite = ns.getSite(webNav.currentURI.spec);
  610.           if (ns.isJSEnabled(curSite)) {
  611.             ns._lastSnapshot.remove(curSite); // force reload
  612.           }
  613.           webNav.allowJavascript = true;
  614.         }
  615.       } else {
  616.         ns.jsEnabled = enabled;
  617.       }
  618.       noscriptOverlay.syncUI();
  619.     }, reloadCurrentTabOnly);
  620.   }
  621. ,
  622.   
  623.   _statusIcon: null,
  624.   get statusIcon() {
  625.     return this._statusIcon || document.getElementById("noscript-statusIcon");
  626.   },
  627.  
  628.   getIcon: function(node) {
  629.     if (typeof(node) != "object") node = document.getElementById(node);
  630.     return node.ownerDocument.defaultView.getComputedStyle(node, null)
  631.             .getPropertyValue("list-style-image")
  632.             .replace(/.*url\s*\(\s*"?(.*)\"?\s*\).*/g, '$1');
  633.   },
  634.   
  635.   getStatusClass: function(lev, inactive, currentClass) {
  636.     return "noscript-" + (inactive ? "inactive-" : "") + lev;
  637.   },
  638.   updateStatusClass: function(node, className) {
  639.     if (!className) className = this.statusIcon.className.replace(/.*(\bnoscript-\S*(?:yes|no|glb|prt|yu|untrusted)).*/, "$1");
  640.     node.className = (node.className.replace(/\bnoscript-\S*(?:yes|no|glb|prt|yu|untrusted)\b/g, "") + " " + className).replace(/\s{2,}/g, " ");
  641.   }
  642. ,
  643.   _syncTimeout: null,
  644.   syncUI: function(w) {
  645.     if (w) {
  646.       if (w != window.content) return;
  647.     } else {
  648.       w = window.content;
  649.     }
  650.     
  651.     if (this._syncTimeout) {
  652.       window.clearTimeout(this._syncTimeout);
  653.     }
  654.     this._syncTimeout = window.setTimeout(function() {
  655.       if (w != window.content) return;
  656.       noscriptOverlay._syncUINow();
  657.     }, 400);
  658.   },
  659.   
  660.   syncXssWidget: function(widget) {
  661.     if (!widget) widget = document.getElementById("noscript-statusXss");
  662.     const ns = this.ns;
  663.     var unsafeRequest = ns.requestWatchdog.getUnsafeRequest(gBrowser.selectedBrowser);
  664.     if (unsafeRequest && !unsafeRequest.issued) {
  665.       widget.removeAttribute("hidden");
  666.       widget.setAttribute("tooltiptext", "XSS [" +
  667.                   ns.getSite(unsafeRequest.origin) + "]->[" + 
  668.                   ns.getSite(unsafeRequest.URI.spec) + "]");
  669.     } else {
  670.       widget.setAttribute("hidden", "true");
  671.     }
  672.   },
  673.   
  674.   syncRedirectWidget: function() {
  675.     var widget = document.getElementById("noscript-statusRedirect");
  676.     var info = this.getMetaRefreshInfo();
  677.     if (!info) {
  678.       widget.setAttribute("hidden", true);
  679.       return;
  680.     }
  681.     widget.removeAttribute("hidden");
  682.     widget.setAttribute("tooltiptext",
  683.         this.getString("metaRefresh.notify.follow") + " [" + info.uri + "]"); 
  684.   },
  685.   
  686.   showUI: function() {
  687.     var statusIcon = this.statusIcon;
  688.     var popup = document.getElementById("noscript-status-popup");
  689.     if (statusIcon.hidden || statusIcon.parentNode.hidden) {
  690.       var tbb = document.getElementById("noscript-tbb");
  691.       if (tbb && window.getComputedStyle(tbb.parentNode, "").display != "none") {
  692.         tbb.open = true;
  693.         return;
  694.       }
  695.       if (statusIcon.parentNode.hidden) {
  696.         window.setTimeout(function() {
  697.           var popup = document.getElementById("noscript-notify-popup");
  698.           var ref = document.getElementById("appcontent");
  699.           popup.showPopup(ref, ref.boxObject.screenX, ref.boxObject.screenY);
  700.         }, 0);
  701.         return;
  702.       } else {
  703.         popup.addEventListener("popuphidden", function(ev) {
  704.             if (ev.currentTarget != ev.target) return;
  705.             ev.target.removeEventListener(ev.type, arguments.callee, false);
  706.             ev.target.parentNode.hidden = !noscriptOverlay.ns.getPref("statusIcon", true);
  707.         }, false);
  708.         statusIcon.hidden = false;
  709.       }
  710.     }
  711.     popup.showPopup();
  712.   }
  713. ,
  714.   get notificationPos() {
  715.     return this.notifyBottom ? "bottom" : "top";
  716.   },
  717.   get altNotificationPos() {
  718.     return this.notificationPos == "top" ? "bottom" : "top";
  719.   }
  720.   getNotificationBox: function(pos, browser) {
  721.     var gb = getBrowser();
  722.     browser = browser || gb.selectedBrowser;
  723.     if (!pos) pos = this.notificationPos;
  724.     
  725.     if (gb.getMessageForBrowser) return gb.getMessageForBrowser(browser, pos); // Fx <= 1.5 
  726.     if (!gb.getNotificationBox) return null; // SeaMonkey
  727.  
  728.     var nb = gb.getNotificationBox(browser);
  729.     
  730.     if (nb && pos == "bottom") 
  731.       this.patchNotificationBox(nb);
  732.    
  733.     return nb;
  734.   },
  735.   patchNotificationBox: function(nb) {
  736.     if (nb._noscriptBottomStack_) return;
  737.     nb._dom_ = {};
  738.     const METHODS = this.notificationBoxPatch;
  739.     for (m in METHODS) {
  740.       nb._dom_[m] = nb[m];
  741.       nb[m] = METHODS[m];
  742.     }
  743.     
  744.     var stacks =  nb.getElementsByTagName("stack");
  745.     var stack = null;
  746.     for (var j = stacks.length; j-- > 0;) {
  747.       if (stacks[j].getAttribute("class") ==  "noscript-bottom-notify") {
  748.         stack = stacks[j];
  749.         break;
  750.       }
  751.     }
  752.     if (!stack) {
  753.      stack = nb.ownerDocument.createElement("stack");
  754.      stack.setAttribute("class", "noscript-bottom-notify");
  755.      nb.appendChild(stack);
  756.     }
  757.     nb._noscriptBottomStack_ = stack;
  758.   },
  759.   
  760.   notificationBoxPatch: {
  761.     insertBefore: function(n, ref) {
  762.       if (n.localName == "notification" && 
  763.           n.getAttribute("value") == "noscript"
  764.           && noscriptOverlay.notificationPos == "bottom") {
  765.         const stack = this._noscriptBottomStack_;
  766.         while (stack.firstChild) 
  767.           stack.removeChild(stack.firstChild);
  768.         
  769.         stack.appendChild(n);
  770.         var hbox = n.ownerDocument.getAnonymousElementByAttribute(
  771.                       n, "class", "notification-inner outset");
  772.         if (hbox) {
  773.           var style = hbox.ownerDocument.defaultView.getComputedStyle(hbox, null);
  774.           var borderProps = ['color', 'style', 'width'];
  775.           var cssProp, jsProp, tmpVal;
  776.           for (var p = borderProps.length; p-- > 0;) {
  777.             cssProp = borderProps[p];
  778.             jsProp = cssProp[0].toUpperCase() + cssProp.substring(1);
  779.             tmpVal = style.getPropertyValue("border-bottom-" + cssProp);
  780.             hbox.style["borderBottom" + jsProp] = style.getPropertyValue("border-top-" + cssProp);
  781.             hbox.style["borderTop" + jsProp] = tmpVal;
  782.           }
  783.         }
  784.         return n;
  785.       }
  786.       if(ref && ref.parentNode != this) {
  787.         var priority = ref.priority;
  788.         ref = null; 
  789.         var notifications = this.allNotifications;
  790.         for (var j = notifications.length; j-- > 0;) {
  791.           if ((ref = notifications[j]).priority < priority && ref.parentNode == this)
  792.             break;
  793.         }
  794.         if(j < 0) ref = null;
  795.       }
  796.       return this._dom_.insertBefore.apply(this, [n, ref]);
  797.     },
  798.     removeChild: function(n) {
  799.       return (n.parentNode == this) ? this._dom_.removeChild.apply(this, arguments) : n.parentNode.removeChild(n); 
  800.     }
  801.   },
  802.   
  803.   getNsNotification: function(widget) {
  804.     if (widget == null) return null;
  805.     if (widget.localName == "notificationbox") return widget.getNotificationWithValue("noscript");
  806.     return this.isNsNotification(widget) && widget || null;
  807.   },
  808.   isNsNotification: function(widget) {
  809.     return widget && widget.getAttribute("value") == "noscript" || widget.popup == "noscript-notify-popup";
  810.   },
  811.   
  812.   
  813.   notificationShow: function(label, icon, canAppend) {
  814.     var box = this.getNotificationBox();
  815.     if (box == null) return false;
  816.     var pos = this.notificationPos;
  817.     
  818.     const gb = getBrowser();
  819.     const browser = gb.selectedBrowser;
  820.     
  821.     var widget = this.getNsNotification(box);
  822.     if (widget) {
  823.      if (widget.localName == "notification") {
  824.        widget.label = label;
  825.        widget.image = icon;
  826.      } else {
  827.        widget.text = label;
  828.        widget.image = icon;
  829.        if (canAppend) widget.removeAttribute("hidden");
  830.      }
  831.     
  832.     } else {
  833.      
  834.       if (!canAppend) return false;
  835.      
  836.       var buttonLabel, buttonAccesskey;
  837.       if (gb.getNotificationBox || /\baButtonAccesskey\b/i.test(gb.showMessage.toSource())) {
  838.         const refWidget = document.getElementById("noscript-options-ctx-menuitem");
  839.         buttonLabel = refWidget.getAttribute("label");
  840.         buttonAccesskey = refWidget.getAttribute("accesskey");
  841.       } else { // Fx < 1.5
  842.         buttonLabel = "";
  843.         buttonAccesskey = "";
  844.       }
  845.       const popup = "noscript-notify-popup";
  846.       if (box.appendNotification) { // >= Fx 2.0
  847.         widget =  box.appendNotification(label, "noscript", icon, box.PRIORITY_WARNING_MEDIUM,
  848.                   [ {label: buttonLabel, accessKey: buttonAccesskey,  popup: popup } ]);
  849.         
  850.       } else if (gb.showMessage) { // Fx <= 1.5.x
  851.         gb.showMessage(browser, icon, label, 
  852.               buttonLabel, null,
  853.               null, popup, pos, true,
  854.               buttonAccesskey);
  855.         widget = this.getNsNotification(box);
  856.       }
  857.      
  858.     }
  859.     if (!widget) return false;
  860.     
  861.     const delay = this.notifyHide && this.notifyHideDelay || 0;
  862.     if (delay) {
  863.      if (this.notifyHideTimeout) window.clearTimeout(this.notifyHideTimeout);
  864.      this.notifyHideTimeout = window.setTimeout(
  865.        function() {
  866.          if (browser == gb.selectedBrowser) {
  867.            noscriptOverlay.notificationHide(browser);
  868.          }
  869.        },
  870.        1000 * delay);
  871.     }
  872.     return true;
  873.   },
  874.   
  875.   getAltNotificationBox: function(browser, value, canAppend) {
  876.     const box = this.getNotificationBox(this.altNotificationPos, browser);
  877.     if (canAppend || (box && 
  878.         box.getNotificationWithValue &&
  879.         box.getNotificationWithValue(value))) return null;
  880.     return box;
  881.   },
  882.   
  883.   notifyXSSOnLoad: function(requestInfo) {
  884.     requestInfo.browser.addEventListener("DOMContentLoaded", function(ev) {
  885.       requestInfo.browser.removeEventListener(ev.type, arguments.callee, false);
  886.       if (requestInfo.unsafeRequest && requestInfo.unsafeRequest.issued) return;
  887.       noscriptOverlay.notifyXSS(requestInfo);
  888.     }, false);
  889.   },
  890.   
  891.   notifyXSS: function(requestInfo) {
  892.     const notificationValue = "noscript-xss-notification"; 
  893.     const box = this.getAltNotificationBox(requestInfo.browser, notificationValue);
  894.     if (!box) return;
  895.  
  896.     var origin = this.ns.getSite(requestInfo.unsafeRequest.origin);
  897.     origin = (origin && "[" + origin + "]") || this.getString("untrustedOrigin");
  898.     var label = this.getString("xss.notify.generic", [origin]);
  899.     var icon = this.getIcon("noscript-statusXss");
  900.     
  901.     const refWidget = document.getElementById("noscript-options-ctx-menuitem");
  902.     var buttonLabel = refWidget.getAttribute("label");
  903.     var buttonAccesskey = refWidget.getAttribute("accesskey");
  904.     var popup = "noscript-xss-popup";
  905.     
  906.     const tabBrowser = getBrowser();
  907.     if (tabBrowser.showMessage) { // Fx 1.5
  908.       tabBrowser.showMessage(
  909.           requestInfo.browser, 
  910.           icon, label, 
  911.           buttonLabel, null,
  912.           null, popup, this.altNotificationPos, true,
  913.           buttonAccesskey);
  914.     } else { // Fx >= 2.0
  915.       box.appendNotification(
  916.         label, 
  917.         notificationValue, 
  918.         icon, 
  919.         box.PRIORITY_WARNING_HIGH,
  920.         [{
  921.           label: buttonLabel,
  922.           accessKey: buttonAccesskey,
  923.           popup: popup
  924.          }]
  925.         );
  926.     }
  927.   },
  928.   
  929.   notifyMetaRefreshCallback: function(info) {
  930.     noscriptOverlay.notifyMetaRefresh(info);
  931.   },
  932.   notifyMetaRefresh: function(info) {
  933.     var browser = this.ns.domUtils.findBrowser(window, info.document.defaultView);
  934.     if (!browser) return;
  935.     
  936.     const notificationValue = "noscript-metaRefresh-notification";
  937.     const box = this.getAltNotificationBox(browser, notificationValue);
  938.     var notification = null;
  939.     
  940.     if (box && this.ns.getPref("forbidMetaRefresh.notify", true)) {
  941.       var label = this.getString("metaRefresh.notify", [info.uri, info.timeout])
  942.       var icon = this.getIcon("noscript-statusRedirect");
  943.         
  944.       if (box.appendNotification) { // Fx 2
  945.       
  946.         notification = box.appendNotification(
  947.           label, 
  948.           notificationValue, 
  949.           icon, 
  950.           box.PRIORITY_INFO_HIGH,
  951.           [{
  952.               label: this.getString("metaRefresh.notify.follow"),
  953.               accessKey: this.getString("metaRefresh.notify.follow.accessKey"),
  954.               callback: function(notification, buttonInfo) {
  955.                 noscriptOverlay.ns.doFollowMetaRefresh(info);
  956.               }
  957.            }]
  958.           );
  959.       }
  960.       browser.addEventListener("beforeunload", function(ev) {
  961.         if (ev.originalTarget == info.document || ev.originalTarget == browser) {
  962.           browser.removeEventListener(ev.type, arguments.callee, false);
  963.           if (notification && notification == box.currentNotification) {
  964.             box.removeCurrentNotification();
  965.           } else {
  966.             noscriptOverlay.ns.doBlockMetaRefresh(info);
  967.           }
  968.           info = browser = null;
  969.         }
  970.       }, false);
  971.     }
  972.     
  973.     this.setMetaRefreshInfo(info, browser);
  974.   },
  975.   
  976.   setMetaRefreshInfo: function(value, browser) {
  977.     return this.ns.setExpando(browser || gBrowser.selectedBrowser, "metaRefreshInfo", value);
  978.   },
  979.   getMetaRefreshInfo: function(browser) {
  980.     return this.ns.getExpando(browser || gBrowser.selectedBrowser, "metaRefreshInfo");
  981.   },
  982.   followMetaRefresh: function(event) {
  983.     this.ns.doFollowMetaRefresh(this.getMetaRefreshInfo(), event.shiftKey);
  984.   },
  985.   
  986.   notifyJarDocument: function(info) {
  987.     var browser = this.ns.domUtils.findBrowser(window, info.document.defaultView.top);
  988.     if (!browser) return false;
  989.     
  990.     const notificationValue = "noscript-jarDoc-notification";
  991.     const box = this.getAltNotificationBox(browser, notificationValue);
  992.   
  993.     if (!(box && box.appendNotification)) return false;
  994.     
  995.     var notification = null;
  996.     
  997.     var label = this.getString("jarDoc.notify", [info.uri]);
  998.     var icon = this.getIcon("noscript-jar-opts");
  999.  
  1000.     notification = box.appendNotification(
  1001.       label, 
  1002.       notificationValue, 
  1003.       icon, 
  1004.       box.PRIORITY_WARNING_HIGH,
  1005.       [{
  1006.           label: this.getString("notify.options"),
  1007.           accessKey: this.getString("notify.accessKey"),
  1008.           callback: function(notification, buttonInfo) {
  1009.             noscriptUtil.openJarOptions();
  1010.           }
  1011.        }]
  1012.       );
  1013.     browser.addEventListener("beforeunload", function(ev) {
  1014.       if (ev.originalTarget == info.document || ev.originalTarget == browser) {
  1015.         browser.removeEventListener(ev.type, arguments.callee, false);
  1016.         if (notification && notification == box.currentNotification) {
  1017.           box.removeCurrentNotification();
  1018.         } 
  1019.         info = browser = notification = null;
  1020.       }
  1021.     }, false);
  1022.     
  1023.     return true;
  1024.   },
  1025.   
  1026.   unsafeReload: function() {
  1027.     const browser = gBrowser.selectedBrowser;
  1028.     const ns = this.ns;
  1029.     const rw = ns.requestWatchdog;
  1030.     var unsafeRequest = rw.getUnsafeRequest(browser);
  1031.     var method;
  1032.     if (!unsafeRequest) {
  1033.       unsafeRequest = {
  1034.         URI: browser.webNavigation.currentURI,
  1035.         origin: rw.traceBackHistory(browser.webNavigation.sessionHistory, browser.contentWindow).join(">>>")
  1036.       };
  1037.       method = "URL";
  1038.     } else {
  1039.       method = (unsafeRequest.postData ? "POST" : "GET");
  1040.     }
  1041.     var msg = noscriptUtil.getString("unsafeReload.warning",
  1042.       [ method, 
  1043.         ns.siteUtils.crop(unsafeRequest.URI.spec), 
  1044.         ns.siteUtils.crop(unsafeRequest.origin || unsafeRequest.referrer && unsafeRequest.referrer.spec || '?')
  1045.       ]);
  1046.     msg += noscriptUtil.getString("confirm");
  1047.     if (noscriptUtil.confirm(msg, "confirmUnsafeReload")) {
  1048.       try {
  1049.         getBrowser().getNotificationBox(browser).removeAllNotifications(true);
  1050.       } catch(e) {}
  1051.       rw.unsafeReload(browser, true);
  1052.     }
  1053.   },
  1054.   
  1055.   notificationHide: function(browser, immediate) { // Modified by Higmmer
  1056.     var box = this.getNotificationBox(null, browser);
  1057.     var widget = this.getNsNotification(box); // Modified by Higmmer
  1058.     if (widget) {
  1059.       if (widget.parentNode) {
  1060.         box = widget.parentNode.parentNode;
  1061.         if (box && box.removeNotification) {
  1062.           if (immediate && box.currentNotification == widget) {
  1063.             box.currentNotification = null;
  1064.           }
  1065.           box.removeNotification(widget);
  1066.         } else if (widget.close) {
  1067.           widget.close();
  1068.         } else {
  1069.           widget.setAttribute("hidden", "true");
  1070.         }
  1071.       }
  1072.       return true;
  1073.     }
  1074.     return false;
  1075.   },
  1076.   
  1077.   _syncUINow: function() {
  1078.     
  1079.     const ns = this.ns;
  1080.     const global = ns.jsEnabled;
  1081.     const jsPSs = ns.jsPolicySites;
  1082.     const untrustedSites = ns.untrustedSites;
  1083.     var lev;
  1084.     
  1085.     this.syncXssWidget();
  1086.     this.syncRedirectWidget();
  1087.     
  1088.     const sites = this.getSites();
  1089.     var totalScripts = sites.scriptCount;
  1090.     var totalPlugins = sites.pluginCount;
  1091.     var totalAnnoyances = totalScripts + totalPlugins;
  1092.     var notificationNeeded = false;
  1093.     var allowedSites = [];
  1094.     var allowed = 0;
  1095.     var untrusted = 0;
  1096.     var isUntrusted = false;
  1097.     if (global && !ns.alwaysBlockUntrustedContent) {
  1098.       lev = "glb";
  1099.     } else {
  1100.       var s = sites.length;
  1101.       var total = s;
  1102.       var url, site;
  1103.       while (s-- > 0) {
  1104.         url = sites[s];
  1105.         isUntrusted = untrustedSites.matches(url);
  1106.         site = !isUntrusted && (global ? url : jsPSs.matches(url));
  1107.         
  1108.         if (site && url == sites.topURL && !gBrowser.selectedBrowser.webNavigation.allowJavascript)
  1109.           site = null;
  1110.           
  1111.         if (site) {
  1112.           if (ns.isPermanent(site) || allowedSites.indexOf(site) > -1) {
  1113.             total--;
  1114.           } else {
  1115.             allowedSites.push(site);
  1116.           }
  1117.         } else {
  1118.           if(!notificationNeeded && url != "about:blank") {
  1119.             if(isUntrusted) untrusted++;
  1120.             else notificationNeeded = true;
  1121.           }
  1122.         }
  1123.       }
  1124.       allowed = allowedSites.length;
  1125.       lev = (allowed == total && sites.length > 0 && !untrusted) ? (global ? "glb" : "yes")
  1126.             : allowed == 0 ? (global ? "untrusted" : "no") 
  1127.             : (untrusted > 0 && !notificationNeeded ? "yu" : "prt");
  1128.       notificationNeeded = notificationNeeded && totalAnnoyances > 0;
  1129.     }
  1130.     
  1131.     var message = this.getString("allowed." +
  1132.         (lev == "yu" ? "prt" : lev == "untrusted" ? "no" : lev));
  1133.     
  1134.     var shortMessage = message.replace(/JavaScript/g, "JS");
  1135.     
  1136.     if (notificationNeeded && allowed) 
  1137.       message += ", " + allowed + "/" + total + " (" + allowedSites.join(", ") + ")";
  1138.     
  1139.     var countsMessage = " | <SCRIPT>: " + totalScripts + " | <OBJECT>: " + totalPlugins;
  1140.     message += countsMessage;
  1141.     shortMessage += countsMessage;
  1142.     
  1143.     var icon = this.getIcon(this.statusIcon);
  1144.     var className = this.getStatusClass(lev, !totalAnnoyances);
  1145.     
  1146.     var widget = document.getElementById("noscript-tbb");
  1147.     if (widget) {
  1148.       widget.setAttribute("tooltiptext", shortMessage);
  1149.       this.updateStatusClass(widget, className); 
  1150.     }
  1151.     
  1152.     widget = this.statusIcon;
  1153.     widget.setAttribute("tooltiptext", shortMessage);
  1154.     this.updateStatusClass(widget, className);
  1155.     
  1156.     if (notificationNeeded) { // notifications
  1157.       const win = window.content;
  1158.       if (this.notify) {
  1159.         this.notificationShow(message,
  1160.           this.getIcon(widget), 
  1161.           !(ns.getExpando(win, "messageShown") && this.notifyHidePermanent));
  1162.         ns.setExpando(win, "messageShown", true);
  1163.       } else {
  1164.         this.notificationHide(); 
  1165.       }
  1166.       if (!ns.getExpando(win, "soundPlayed")) {
  1167.         ns.soundNotify(window.content.location.href);
  1168.         ns.setExpando(win, "soundPlayed");
  1169.       }
  1170.     } else {
  1171.       this.notificationHide();
  1172.       message = shortMessage = "";
  1173.     }
  1174.     
  1175.     widget = document.getElementById("noscript-statusLabelValue");
  1176.     widget.setAttribute("value", shortMessage);
  1177.     widget.parentNode.style.display = message ? "block" : "none";
  1178.   }
  1179. ,
  1180.   notifyHideTimeout: 0
  1181. ,
  1182.   
  1183.   initContentWindow: function(window) {
  1184.     window.addEventListener("pagehide", this.listeners.onPageHide, true);
  1185.   },
  1186.   
  1187.   cleanupDocument: function(doc, browser) {
  1188.     
  1189.     if (!(doc.defaultView && doc.defaultView == doc.defaultView.top)) return;
  1190.     
  1191.     const ns = this.ns;
  1192.     browser = browser || ns.domUtils.findBrowserForNode(doc);
  1193.     if (browser) {
  1194.       ns.setExpando(browser, "pe", null);
  1195.       this.notificationHide(browser, true);
  1196.     }
  1197.   },
  1198.   
  1199.   prefsObserver: {
  1200.     ns: noscriptUtil.service,
  1201.     QueryInterface: noscriptUtil.service.generateQI([
  1202.         Components.interfaces.nsISupports, 
  1203.         Components.interfaces.nsIObserver, 
  1204.         Components.interfaces.nsISupportsWeakReference])
  1205.   ,
  1206.     observe: function(subject, topic, data) {
  1207.       if (subject == this.ns.caps) {
  1208.          noscriptOverlay.syncUI();
  1209.          return;
  1210.       }
  1211.       switch (data) {
  1212.         case "statusIcon": case "statusLabel":
  1213.           window.setTimeout(function() {
  1214.               var widget =document.getElementById("noscript-" + data);
  1215.               if (widget) {
  1216.                 widget.setAttribute("hidden", !noscriptOverlay.ns.getPref(data))
  1217.               }
  1218.             }, 0);
  1219.          break;
  1220.          case "notify":
  1221.          case "notify.bottom":
  1222.            noscriptOverlay[data.replace(/\.b/, 'B')] = this.ns.getPref(data);
  1223.            if(this._registered) noscriptOverlay.notificationHide();
  1224.          break;
  1225.          case "keys.ui":
  1226.          case "keys.toggle":
  1227.            noscriptOverlay.shortcutKeys.setup(data.replace(/^keys\./, ""), this.ns.getPref(data, ""));
  1228.            break;
  1229.          break;
  1230.          case "notify.hidePermanent":
  1231.          case "notify.hideDelay":
  1232.          case "notify.hide":
  1233.            noscriptOverlay[data.replace(/\.h/, 'H')] = this.ns.getPref(data);
  1234.          break;
  1235.       }
  1236.     },
  1237.     _registered: false,
  1238.     register: function() {
  1239.       this.ns.prefs.addObserver("", this, true);
  1240.       this.ns.caps.addObserver("", this, true);
  1241.       const initPrefs = [
  1242.         "statusIcon", "statusLabel", 
  1243.         "keys.ui", "keys.toggle",
  1244.         "notify", "notify.bottom",
  1245.         "notify.hide", "notify.hidePermanent", "notify.hideDelay"
  1246.         ];
  1247.       for (var j = 0; j < initPrefs.length; j++) {
  1248.         this.observe(null, null, initPrefs[j]);
  1249.       }
  1250.       this._registered = true;
  1251.     },
  1252.     remove: function() {
  1253.       this.ns.prefs.removeObserver("", this);
  1254.       this.ns.caps.removeObserver("", this);
  1255.     }
  1256.   },
  1257.   
  1258.   
  1259.   
  1260.   
  1261.   
  1262.   shortcutKeys: {
  1263.     
  1264.     execute: function(cmd) {
  1265.       switch (cmd) {
  1266.         case 'toggle':
  1267.           noscriptOverlay.toggleCurrentPage(noscriptOverlay.ns.preferredSiteLevel);
  1268.           break;
  1269.         case 'ui':
  1270.            noscriptOverlay.showUI();
  1271.            break;
  1272.       }
  1273.     },
  1274.     
  1275.     keys: {},
  1276.     setup: function(name, values) { 
  1277.       values = values.toLowerCase().replace(/^\s*(.*?)\s*$/g, "$1").split(/\s+/);
  1278.       var vpos = values.length;
  1279.       if (vpos) {
  1280.         
  1281.         var mods = { shiftKey: false, altKey: false, metaKey: false, ctrlKey: false };
  1282.         
  1283.         var keyVal = values[--vpos];
  1284.         for (var value; vpos-- > 0;) {
  1285.           value = values[vpos] + "Key";
  1286.           if (value in mods) {
  1287.             mods[value] = true;
  1288.           }
  1289.         }
  1290.         
  1291.         var key = { modifiers: mods, charCode: 0, keyCode: 0 };
  1292.         
  1293.         if (keyVal.length > 3) {
  1294.           var pos = keyVal.indexOf('.');
  1295.           if (pos > 3) {
  1296.             key.charCode = keyVal.charCodeAt(pos + 1) || 0;
  1297.             keyVal = keyVal.substring(0, pos);
  1298.           }
  1299.           key.keyCode = KeyEvent["DOM_" + keyVal.toUpperCase()] || 0;
  1300.         } else {
  1301.           key.charCode = (key.modifiers.shiftKey ? keyVal.toUpperCase() : keyVal).charCodeAt(0) || 0;
  1302.         }
  1303.         
  1304.         this.keys[name] = key;
  1305.       } else {
  1306.         delete(this.keys[name]);
  1307.       }
  1308.     },
  1309.     listener: function(ev) {
  1310.       const binding = arguments.callee.binding;
  1311.       const skk = binding.keys;
  1312.       var cmd, k, p, sk, mods;
  1313.       for (k in skk) {
  1314.         cmd = k;
  1315.         sk = skk[k];
  1316.         
  1317.          
  1318.         if (ev.charCode && ev.charCode == sk.charCode || ev.keyCode && ev.keyCode == sk.keyCode) {
  1319.           mods = sk.modifiers;
  1320.           for (p in mods) {
  1321.             if (ev[p] != mods[p]) {
  1322.               cmd = null;
  1323.               break;
  1324.             }
  1325.           }
  1326.           
  1327.           
  1328.           if (cmd) {
  1329.             ev.preventDefault();
  1330.             binding.execute(cmd);
  1331.             return;
  1332.           }
  1333.         }
  1334.       }
  1335.     },
  1336.     
  1337.     register: function() {
  1338.       this.listener.binding = this;
  1339.       window.addEventListener("keypress", this.listener, true);
  1340.     },
  1341.     remove: function() {
  1342.       window.removeEventListener("keypress", this.listener, true);
  1343.     }
  1344.   },
  1345.   
  1346.   hideObject: function(p, o) {
  1347.     if (!p.mimeRx.test(o.type)) return;
  1348.     
  1349.     var r = p.document.createElement("object");
  1350.     r.style.width = o.offsetWidth + "px";
  1351.     r.style.height = o.offsetHeight + "px";
  1352.     r.style.display = "inline-block";
  1353.     o.className += " " + p.className;
  1354.     o.parentNode.insertBefore(r, o);
  1355.   },
  1356.   
  1357.   showObject: function(p, o) {
  1358.     var cs = o.className;
  1359.     cs = cs.replace(p.classRx, '');
  1360.     if (cs != o.className) {
  1361.       o.className = cs;
  1362.       var r = o.previousSibling;
  1363.       if (r instanceof HTMLObjectElement) {
  1364.         r.parentNode.removeChild(r);
  1365.       }
  1366.     }
  1367.   },
  1368.   
  1369.   _tags: ["object", "embed"],
  1370.   toggleObjectsVisibility: function(d, v) {
  1371.     var ns = noscriptOverlay.ns;
  1372.     var rx = ns.hideOnUnloadRegExp;
  1373.     if (!rx) return;
  1374.     var callback = v ? noscriptOverlay.showObject : noscriptOverlay.hideObject;
  1375.     var params = {
  1376.       document: d,
  1377.       mimeRx: rx,
  1378.       classRx: noscriptOverlay.ns.hideObjClassNameRx,
  1379.       className: ns.hideObjClassName
  1380.     };
  1381.     var aa = null;
  1382.     var j;
  1383.     for each(var t in this._tags) {
  1384.       var oo = d.getElementsByTagName(t);
  1385.       j = oo.length;
  1386.       if (j) {
  1387.         aa = aa || [oo[--j]];
  1388.         while(j-- > 0) {
  1389.           aa.push(oo[j]);
  1390.         }
  1391.       }
  1392.     }
  1393.     if (aa) {
  1394.       for (j = aa.length; j-- > 0;) {
  1395.         callback(params, aa[j]);
  1396.       }
  1397.     }
  1398.   },
  1399.   
  1400.   listeners: {
  1401.     
  1402.     onBrowserClick: function(ev) { 
  1403.       noscriptUtil.service.processBrowserClick(ev);
  1404.     },
  1405.   
  1406.     
  1407.     onTabClose: function(ev) {
  1408.       try {
  1409.         var browser = ev.target.linkedBrowser;
  1410.         noscriptOverlay.ns.cleanupBrowser(browser);
  1411.         
  1412.         var tabbrowser = getBrowser();
  1413.         if (tabbrowser._browsers) tabbrowser._browsers = null;
  1414.         if (tabbrowser.getNotificationBox) {
  1415.           tabbrowser.getNotificationBox(browser).removeAllNotifications(true);
  1416.         }
  1417.       } catch(e) {}
  1418.     },
  1419.     
  1420.     webProgressListener: {
  1421.       QueryInterface: noscriptUtil.service.generateQI([
  1422.         Components.interfaces.nsIWebProgressListener]),
  1423.       STATE_STOP: Components.interfaces.nsIWebProgressListener.STATE_STOP,
  1424.       onLocationChange: function(aWebProgress, aRequest, aLocation) {
  1425.         const domWindow = aWebProgress.DOMWindow;
  1426.         if (domWindow) {
  1427.           noscriptOverlay.syncUI(domWindow);
  1428.         }
  1429.       },
  1430.       onStatusChange: function() {}, 
  1431.       onStateChange: function(aWebProgress, aRequest, stateFlags, status) {
  1432.         if (stateFlags & this.STATE_STOP) {
  1433.           const domWindow = aWebProgress.DOMWindow;
  1434.           if (domWindow == domWindow.top) {
  1435.             noscriptOverlay.syncUI(domWindow);
  1436.           }
  1437.         } 
  1438.       }, 
  1439.       onSecurityChange: function() {}, 
  1440.       onProgressChange: function() {}
  1441.     },
  1442.     
  1443.     onContentLoad: function(ev) {
  1444.  
  1445.       var doc = ev.originalTarget;
  1446.       if (doc instanceof HTMLDocument) {
  1447.         var w = doc.defaultView;
  1448.         if (w) {
  1449.           const ns = noscriptOverlay.ns;
  1450.           noscriptOverlay.ns.setExpando(w, "contentLoaded", true);
  1451.           if (w == w.top) {
  1452.             ns.processMetaRefresh(doc, noscriptOverlay.notifyMetaRefreshCallback);
  1453.             if (w == window.content) {
  1454.               noscriptOverlay._syncUINow();
  1455.             }
  1456.           } else {
  1457.             noscriptOverlay.syncUI(w.top);
  1458.           }
  1459.           w.addEventListener("load", noscriptOverlay.listeners.onDocumentLoad, false);
  1460.         }
  1461.       }
  1462.     },
  1463.     onDocumentLoad: function(ev) {
  1464.       if (ev.originalTarget instanceof HTMLDocument) {
  1465.         ev.currentTarget.removeEventListener("load", arguments.callee, false);
  1466.         ev.currentTarget.setTimeout(function() {
  1467.           noscriptOverlay.ns.detectJSRedirects(this.document);
  1468.         }, 0);
  1469.       }
  1470.     },
  1471.     
  1472.     onPageShow: function(ev) {
  1473.       if (ev.persisted && (ev.target instanceof HTMLDocument)) {
  1474.         noscriptOverlay.toggleObjectsVisibility(ev.target, true);
  1475.       }
  1476.     },
  1477.     onPageHide: function(ev) {
  1478.       var d = ev.target;
  1479.       if (d instanceof HTMLDocument) {
  1480.         noscriptOverlay.cleanupDocument(d);
  1481.         noscriptOverlay.toggleObjectsVisibility(d, false);
  1482.       }
  1483.     },
  1484.     
  1485.     onContextMenu:  function(ev) { noscriptOverlay.prepareContextMenu(ev) },
  1486.     
  1487.     onLoad: function(ev) {
  1488.       window.removeEventListener("load", arguments.callee, false);
  1489.       window.addEventListener("unload", noscriptOverlay.listeners.onUnload, false);
  1490.       try {
  1491.         noscriptOverlay.listeners.setup(); 
  1492.         noscriptOverlay.wrapBrowserAccess();
  1493.         window.setTimeout(noscriptOverlay.pdfDownloadHack, 0);
  1494.       } catch(e) {
  1495.         var msg = "[NoScript] Error initializing new window " + e + "\n"; 
  1496.         noscriptOverlay.ns.log(msg);
  1497.         noscriptOverlay.ns.dump(msg);
  1498.       }
  1499.     },
  1500.     onUnload: function(ev) {
  1501.       window.removeEventListener("unload", arguments.callee, false);
  1502.       noscriptOverlay.listeners.teardown();
  1503.       window.browserDOMWindow = null;
  1504.       noscriptOverlay.dispose();
  1505.     },
  1506.     
  1507.     setup: function() {
  1508.       
  1509.       var context = document.getElementById("contentAreaContextMenu");
  1510.       if (!context) return; // not a browser window?
  1511.       
  1512.       context.addEventListener("popupshowing", this.onContextMenu, false);
  1513.      
  1514.       var b = getBrowser();
  1515.         
  1516.       b.addEventListener("click", this.onBrowserClick, true);
  1517.      
  1518.       const nsIWebProgress = Components.interfaces.nsIWebProgress;
  1519.       b.addProgressListener(this.webProgressListener, nsIWebProgress.NOTIFY_STATE_WINDOW | nsIWebProgress.NOTIFY_LOCATION);
  1520.   
  1521.       if (b.tabContainer) {
  1522.         b.tabContainer.addEventListener("TabClose", this.onTabClose, false);
  1523.       }
  1524.       
  1525.       window.addEventListener("DOMContentLoaded", this.onContentLoad, false);
  1526.       
  1527.       
  1528.       window.addEventListener("pageshow", this.onPageShow, true);
  1529.       window.addEventListener("pagehide", this.onPageHide, true);
  1530.  
  1531.       noscriptOverlay.shortcutKeys.register();
  1532.       noscriptOverlay.prefsObserver.register();
  1533.  
  1534.       window.setTimeout(noscriptOverlay.firstRunCheck, 10);
  1535.  
  1536.     },
  1537.     
  1538.     
  1539.    
  1540.     teardown: function() {
  1541.  
  1542.       var b = getBrowser();
  1543.       if (b) {
  1544.         b.removeEventListener("click", this.onBrowserClick, true);
  1545.         if (b.tabContainer) {
  1546.           b.tabContainer.removeEventListener("TabClose", this.onTabClose, false);
  1547.         }
  1548.         
  1549.         b.removeProgressListener(this.webProgressListener);
  1550.       }
  1551.       
  1552.       window.removeEventListener("pagehide", this.onPageHide, true);
  1553.       window.removeEventListener("pageshow", this.onPageShow, true);
  1554.       window.removeEventListener("DOMContentLoaded", this.onContentLoad, false);
  1555.  
  1556.       noscriptOverlay.prefsObserver.remove();
  1557.       noscriptOverlay.shortcutKeys.remove();
  1558.       
  1559.       document.getElementById("contentAreaContextMenu")
  1560.               .removeEventListener("popupshowing", this.onContextMenu, false);
  1561.               
  1562.     }
  1563.     
  1564.   }, // END listeners
  1565.   
  1566.   firstRunCheck: function() {
  1567.     var ns = noscriptUtil.service;
  1568.     const prevVer = ns.getPref("version", "");
  1569.     if (prevVer != ns.VERSION) {
  1570.       ns.setPref("version", ns.VERSION);
  1571.       if (prevVer && prevVer < "1.1.4.070304") ns.sanitize2ndLevs();
  1572.       if (ns.getPref("firstRunRedirection", true)) {
  1573.           window.setTimeout(function() {
  1574.             const url = "http://noscript.net?ver=" + noscriptUtil.service.VERSION + "&prev=" + prevVer;
  1575.             const browser = getBrowser();
  1576.             browser.selectedTab = browser.addTab(url, null);
  1577.             noscriptUtil.service.savePrefs();
  1578.           }, 100);
  1579.        }
  1580.     }
  1581.   },
  1582.   
  1583.  
  1584.   
  1585.   wrapBrowserAccess: function() { // called onload
  1586.     if (!window.nsBrowserAccess) {
  1587.       noscriptOverlay.ns.log("[NoScript] nsBrowserAccess not found?!");
  1588.       return;
  1589.     }
  1590.   
  1591.     if (!nsBrowserAccess.prototype.wrappedJSObject) {
  1592.       nsBrowserAccess.prototype.__defineGetter__("wrappedJSObject", noscriptOverlay.browserAccess.self);
  1593.     }
  1594.     
  1595.     if (!(window.browserDOMWindow && browserDOMWindow.wrappedJSObject && (browserDOMWindow.wrappedJSObject instanceof nsBrowserAccess))) {
  1596.       if (!'retryCount' in arguments.callee) {
  1597.         arguments.callee.retryCount = 10;
  1598.       } else if (arguments.callee.retryCount) {
  1599.         noscriptOverlay.ns.log("[NoScript] browserDOMWindow not found or not set up, retrying " + arguments.callee.retryCount + " times");
  1600.         arguments.callee.retryCount--;
  1601.       }
  1602.       window.setTimeout(arguments.callee, 0);
  1603.       return;
  1604.     }
  1605.     
  1606.     browserDOMWindow.wrappedJSObject.openURI = noscriptOverlay.browserAccess.openURI;
  1607.     
  1608.     if(noscriptOverlay.ns.consoleDump) 
  1609.       noscriptOverlay.ns.dump("[NoScript] browserDOMWindow wrapped for external load interception");
  1610.   },
  1611.   
  1612.   browserAccess: {
  1613.     self: function() { return this; },
  1614.     openURI: function(aURI, aOpener, aWhere, aContext) {
  1615.       const ns = noscriptUtil.service;
  1616.  
  1617.       var external = aContext == Components.interfaces.nsIBrowserDOMWindow.OPEN_EXTERNAL && aURI;
  1618.       if (external) {
  1619.         if (aURI.schemeIs("http") || aURI.schemeIs("https")) {
  1620.            // remember for filter processing
  1621.            ns.requestWatchdog.externalLoad = aURI.spec;
  1622.         } else {
  1623.            // don't let the external protocol open dangerous URIs
  1624.            if (aURI.schemeIs("javascript") || aURI.schemeIs("data")) {
  1625.              var err = "[NoScript] external non-http load blocked: " + aURI.spec;
  1626.              ns.log(err);
  1627.              throw err;
  1628.            }
  1629.         }
  1630.       }
  1631.       
  1632.       if (aURI && ns.extraCapturedProtocols && ns.extraCapturedProtocols.indexOf(aURI.scheme) > -1) {
  1633.         return aOpener || window.content;
  1634.       }
  1635.       
  1636.       var w = null;
  1637.       try {
  1638.         w = nsBrowserAccess.prototype.openURI.apply(this, arguments);
  1639.         if (external) ns.dump("[NoScript] external load intercepted");
  1640.       } finally {
  1641.         if (external && !w) ns.requestWatchdog.externalLoad = null;
  1642.       }
  1643.       return w;
  1644.     }
  1645.   },
  1646.   
  1647.   pdfDownloadHack: function() {
  1648.     if (typeof(mouseClick) != "function") return;
  1649.     var tb = getBrowser();
  1650.     tb.removeEventListener("click", mouseClick, true);
  1651.     tb.addEventListener("click", mouseClick, false);
  1652.   },
  1653.   
  1654.   install: function() {
  1655.     // this.ns.dump("*** OVERLAY INSTALL ***\n");
  1656.     this.ns.setPref("badInstall", false);
  1657.     this.ns.domUtils._winType = document.documentElement.getAttribute("windowtype");
  1658.     window.addEventListener("load", this.listeners.onLoad, false);
  1659.   },
  1660.  
  1661.   dispose: function() {
  1662.  
  1663.     for (var bb = getBrowser().browsers, j = bb.length; j-- > 0;) {
  1664.       try {
  1665.         this.cleanupDocument(bb[j].contentWindow.document, bb);
  1666.       } catch(e) {
  1667.         this.ns.dump(e);
  1668.       }
  1669.       this.ns.cleanupBrowser(bb[j]);
  1670.     }
  1671.     // this.ns.dump("*** OVERLAY DISPOSE ***\n");
  1672.   }
  1673. } : {
  1674.   install: function() {
  1675.     window.addEventListener("load", function(ev) {
  1676.       ev.currentTarget.removeEventListener("load", arguments.callee, false); 
  1677.       var node = null;
  1678.       for each(var id in ["noscript-context-menu", "noscript-tbb", "noscript-statusIcon"]) {
  1679.         node = document.getElementById(id);
  1680.         if (node) node.hidden = true;
  1681.       }
  1682.       node = null;
  1683.       var prefs = this.prefService = Components.classes["@mozilla.org/preferences-service;1"]
  1684.         .getService(Components.interfaces.nsIPrefService).getBranch("noscript.");
  1685.       try {
  1686.         if (prefs.getBoolPref("badInstall")) return;
  1687.       } catch(e) {}
  1688.       prefs.setBoolPref("badInstall", true);
  1689.       prefs = null;
  1690.       window.setTimeout(function() {
  1691.         alert("NoScript is not properly installed and cannot operate correctly.\n" + 
  1692.               "Please install it again and check the Install FAQ section on http://noscript.net/faq if this problem persists.");
  1693.         gBrowser.selectedTab = gBrowser.addTab("http://noscript.net/faq#faqsec2", null);
  1694.       },10);
  1695.     }, false);
  1696.   }
  1697. }
  1698. noscriptOverlay.install();
  1699.  
  1700.